package org.opens.javaskill.design;

import lombok.Data;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.stream.IntStream;

/**
 * 功能:
 * <p>享元模式比较难以理解</p>
 * 说明:
 * <pre>
 *     1. 感觉上这个类是使用HashMap缓存了内存中的大量对象; 这样就和原型模式较为相似了.
 *     2. 使用场景可能是这些大量的对象大部分都是相同的, 只有小部分属性不一样, 使用这个享元模式之后, 可以保证内存中真实的对象只有特征值
 *     的个数个, 其他属性在取出这个对象时进行动态设置.
 * </pre>
 */
public class FlyweightPattern {

    private static String[] colorArr = new String[]{"red", "green", "yellow", "blue", "white"};

    private static Random random = new Random();

    public static void main(String[] args) {
        IntStream.rangeClosed(0, 100).forEach(x -> {
            DrawCircle circle = ShapeFactory.getCircle(colorArr[random.nextInt(5)]);
            if ( circle instanceof MyDrawCircle ) {
                MyDrawCircle myDrawCircle = (MyDrawCircle) circle;
                myDrawCircle.setX(random.nextInt(100));
                myDrawCircle.setY(random.nextInt(100));
                myDrawCircle.setRadius(random.nextInt(100));
            }
            circle.draw();
        });
        System.out.println(ShapeFactory.getCircleMapSize());
    }

}

/**
 * 功能:
 * <p>这个接口用来声明一个画圆接口</p>
 * 说明:
 * <pre>
 *     1. draw方法表示绘制一个圆.
 * </pre>
 */
interface DrawCircle {

    void draw();

}

@Data
class MyDrawCircle implements DrawCircle {

    private int x;

    private int y;

    private int radius;

    private String color;

    public MyDrawCircle() {
    }

    public MyDrawCircle(String color) {
        this.color = color;
    }

    @Override
    public void draw() {
        System.out.println(this);
    }

}

class ShapeFactory {

    private static final Map<String, DrawCircle> circleMap = new HashMap<>();

    public static DrawCircle getCircle(String color) {
        DrawCircle circle = circleMap.get(color);
        if ( circle == null ) {
            circle = new MyDrawCircle(color);
            circleMap.put(color, circle);
        }
        return circle;
    }

    public static int getCircleMapSize() {
        return circleMap.size();
    }

}